test();

function test() {
    testTime();
    testMail('15001933144', '19302010020@fudan.edu.cn');
    testMail('150019331443', '19302010020@fudan.edu.cn');
    testMail('15001933144', '19302010020*@fudan.edu.cn');
    testMail('12001933144', '19302010020@复旦.edu.cn');
    testRedundancy('a a b B b');
    testRedundancy('love love is more than a A a word，\n' +
    '\n' +
    'it says so so much.\n' +
    '\n' +
    'When I see sEe these ThEse four letters,\n' +
    '\n' +
    'I almost FeeL fEEl your touch.\n' +
    '\n' +
    'This is Is only happened since，\n' +
    '\n' +
    'I fell in love Love with you.\n' +
    '\n' +
    'Why this word does this This,\n' +
    '\n' +
    'I i haven\'t got a clue Clue clue.');
    testKeyBoard('7_This_is_a_test', '_hs_s_a_es');
    testSpecialReverse("   Hellow  world!");
    twoSum([14, 5,0, 3, 21, -4, 7], 10);
    lengthOfLongestSubstring("123431");
    lengthOfLongestSubstring("abcdefgaf");
}

/*
1.
背景：
    每隔五秒运行一次函数直到某一整分钟停止，比如从20:55:45运行到20:56:00停止；
    或者运行10次，先到的为准。从1开始每过五秒，输入框内数值翻倍。初始值为1。
注意：
    你可以在函数 timeTest内部 和 timeTest外部 写代码使得该功能实现。
要求：
    ①要求使用JS闭包的方式使得计数实现局部私有，不可以在全局区域声明计数变量。
    ②使用console.log打印计数即可，到达一分钟提前停止也需要console.log相应的提示语句。
*/
function testTime() {
    function Counter(){
        let count=0;

        this.getCount=function(){
            return count;
        };

        this.addCount=function(){
            return count++;
        };
    }

    let num, count=new Counter(), date, minute, second, intervalID;
    function init() {
        date = new Date();
        num = 1;
        console.log(num);
        minute = date.getMinutes();
        second = date.getSeconds();
        intervalID = setInterval(function check() {
            const dateCurrent = new Date(),
                minuteCurrent = dateCurrent.getMinutes(),
                secondCurrent = dateCurrent.getSeconds();
            if (minuteCurrent !== minute) {//达到整分钟，停止
                console.log("现在达到" + minuteCurrent + ":00,停止计数,已翻倍" + count.getCount() + "次");
                clearInterval(intervalID);
            }
            if (count.getCount() === 10) {
                clearInterval(intervalID);
            }
            if (secondCurrent === second + 5) {//经过5秒，翻倍并打印
                addNum();
            }
        }, 1000);
    }

    function addNum() {
        num *= 2;
        second += 5;
        count.addCount();
        console.log(num);
    }


    return init();
}

/*
2.
要求：
    ①能够对传入的、移动手机电话（11位）、邮箱字符串（上网查找其要求）进行正则判定。
    ②使用console.log打印即可，例如，电话不符合要求但是邮箱符合要求，则console.log("The telephone is right and the mail is wrong!")。
    ③邮箱字符串的正则匹配的理解需写入lab文档。
    ④telephone与mail均是字符串。
*/
function testMail(telephone, mail) {
    const telephoneReg = /^1[3456789]\d{9}$/;
    const mailReg = /^[\w-]+@[\w-]+(\.[\w-]+)+$/;
    if (telephoneReg.test(telephone)) {
        if (mailReg.test(mail)) {
            console.log("Both are correct")//都正确
        } else {
            console.log("The telephone is correct but the mail is wrong")//电话对，邮件错
        }
    } else {
        if (mailReg.test(mail)) {
            console.log("The telephone is wrong but the mail is correct")//电话错，右键对
        } else {
            console.log("Both are wrong")//都错误
        }
    }
}

/*
3.
要求：
    ①输入一段全英文语句，要求使用正则表达式找到相邻的重复单词放入一个Set，如果集合中元素超过10个，则按照首字母顺序取前10个于集合。
    ②使用console.log打印即可，将该集合打印出来。
    ③例如：输入"Is is the iS is cost of of gasoline going up up"，输出：Set { 'Is is', 'iS is', 'of of', 'up up' }。
    ④对该函数中用的正则匹配的理解需写入lab文档。
    ⑤str为字符串。
*/
function testRedundancy(str) {
    const repetitionReg = /(\b\w+\b)\s\1+/ig;
    const array = [];

    while (true) {
        //console.log(str);
        let result = repetitionReg.exec(str);
        //console.log(result);
        if (result === null) {
            break;
        }
        array.push(result[0]);
        repetitionReg.lastIndex -= (result[0].length - 1) / 2;
    }


    array.sort(function (value1, value2) {
        if (value1.toLowerCase() < value2.toLowerCase()) {
            return -1;
        } else if (value1.toLowerCase() > value2.toLowerCase()) {
            return 1;
        } else {
            return 0;
        }
    });

    const set = new Set();
    for (let i = 0; i < array.length; i++) {
        if (set.size < 10) {
            set.add(array[i]);
        } else {//提前结束循环
            break;
        }
    }
    console.log(set);
}

/*
4.
背景：
    旧键盘上坏了几个键，于是在敲一段文字的时候，对应的字符就不会出现。
    现在给出应该输入的一段文字、以及实际被输入的文字，请你使用Set列出肯定坏掉的那些键。
    例如：输入7_This_is_a_test和_hs_s_a_es    输出：Set { '7', 'T', 'I' }
要求：
    ①需要使用Set。
    ②只能使用一次循环。
    ③使用console.log打印即可，将该集合打印出来。
    ④wantInput和actualInput为字符串。
注意：
    ①注意联系生活，并注意观察我给的上述例子。
*/
function testKeyBoard(wantInput, actualInput) {
    let index1 = 0, index2 = 0, setBroken = new Set();

    while (index2 <= actualInput.length) {
        if (wantInput.charAt(index1) === actualInput.charAt(index2)) {
            index1++;
            index2++;
        } else {
            setBroken.add(wantInput.charAt(index1).toUpperCase());
            index1++;
        }
    }

    console.log(setBroken);
}

/*
5.
背景：
    给定一个输入英文语句字符串，反转该语句。例如the sky is blue变成blue is sky the。
要求：
    ①如果输入的字符串前后有空格，输出中应该去除前后空格。如果输入字符串中间出现连续的两个空格，输出应该变为一个。
    比如输入是“  hello  world!  ”，输出应该是“world! hello”。
    ②请使用Array。
    ③使用console.log打印即可，将该数组打印出来。
    ④只能显式使用一次循环。
    ⑤str为字符串。
*/
function testSpecialReverse(str) {
    let arrayStr = str.split(' ');//按空格分割，并删去空项（即两个相邻空格所夹）
    arrayStr = arrayStr.filter(function (item) {
        return (item !== '');
    });
    //反转后重构为字符串
    arrayStr.reverse();
    console.log(arrayStr.join(" "));
}

/*
6.
背景：
    给定一个整数数组和一个值，找出相加为该值的两个元素下标并保存在一个数组中。
    例如给定 [2, 7, 11, 15]和9,
    打印结果为[0,1]
要求：
    ①使用Map。
    ②只能显式使用一次循环。
    ③使用console.log打印即可，将满足条件的数组打印出来。
    ④nums为数字数组，如[1,2,3,4],target为数字,如5，那么输出为
    [ 0, 3 ]
    [ 1, 2 ]
*/

function twoSum(nums, target) {
    const map = new Map();
    let result = [];
    for (let i = 0; i < nums.length; i++) {
        map.set(nums[i], i);
        if (map.has(target - nums[i]) && i !== map.get(target - nums[i])) {
            result.push([i, map.get(target - nums[i])].reverse());//直接查找出来是先大后小，转换一下更加人性化
        }
    }
    console.log(result);
}


/*
7.
背景：
    打印最长的包含不同字符串的子字符串长度。
要求：
    ①使用Map。
    ②例如：输入"abbbbb",输出1，输入"bbbbb",输出2；
    ③只能显式使用一次循环。
    ④使用console.log打印即可。
    ⑤str为字符串。
*/
function lengthOfLongestSubstring(str) {
    let indexLeft = 0, indexRight = 0, map = new Map(), result = 0;

    while (indexRight < str.length) {
        if (map.has(str.charAt(indexRight))) {
            indexLeft = Math.max(indexLeft, map.get(str.charAt(indexRight)) + 1);
        }
        map.set(str.charAt(indexRight), indexRight);
        result = Math.max(result, indexRight - indexLeft + 1);
        indexRight++;
    }
    console.log(result);
}

/*
8.
背景：
    该部分只是为了让你们自己动动手更好地感受不同继承方式。
要求：
    ①借助构造函数、原型链、和Object.create分别编写DevelopingCountry、PoorCountry、DevelopedCountry以实现对Country的继承，
    并在三者分别添加sayHi、saySad、sayHappy函数分别打印"Hi,i am a developing country."、"I am a sad poor country."、"I am a Happy developed country."
    ②请调用他们并打印相关语句即可。
*/

function Country() {
    this.name = "国家";
}

//构造函数，缺陷在于父类的方法都会被重复创造，函数复用无从谈起
function DevelopingCountry() {
    Country.call(this);
}

DevelopingCountry.prototype.sayHi = function () {
    console.log("Hi,i am a developing country.");
};

//原型链，缺陷在于引用类型都会共享
function PoorCountry() {
}

PoorCountry.prototype = new Country();
PoorCountry.prototype.saySad = function () {
    console.log("I am a sad poor country.");
};

//object.create,无构造函数，只想让一个对象继承一个对象时适合
developedCountry = Object.create(new Country());

developedCountry.sayHappy = function () {
    console.log("I am a happy developed country.");
};

function test8() {
    let developingCountry = new DevelopingCountry();
    developingCountry.sayHi();
    let poorCountry = new PoorCountry();
    poorCountry.saySad();
    developedCountry.sayHappy();
}

test8();